'''
缺失值得相关函数
'''
import pandas as pd
import numpy as np
df = pd.read_csv('data/learn_pandas.csv',
                 usecols = ['Grade', 'Name', 'Gender', 'Height',
                            'Weight', 'Transfer'])
df.isna().head()
df.isna().mean() # 查看缺失的比例
# 获取height为nan的
df[df.Height.isna()].head()
sub_set = df[['Height', 'Weight', 'Transfer']]
df[sub_set.isna().all(1)] # 全部缺失
df[sub_set.isna().any(1)].head() # 至少有一个缺失
df[sub_set.notna().all(1)].head() # 没有缺失

'''
根据缺失值进行数据清洗
'''
res = df.dropna(how = 'any', subset = ['Height', 'Weight'])

res = df.dropna(1, thresh=df.shape[0]-15) # 身高被删除
# 与上述相同效果
res = df.loc[df[['Height', 'Weight']].notna().all(1)]
res = df.loc[:, ~(df.isna().sum()>15)]

'''
填充缺失值得行或列
'''
s = pd.Series([np.nan, 1, np.nan, np.nan, 2, np.nan],
               list('aaabcd'))
s.fillna(method='ffill') # 用前面的值向后填充
s.fillna(method='ffill', limit=1) # 连续出现的缺失，最多填充一次
s.fillna(s.mean()) # value为标量
s.fillna({'a': 100, 'd': 200}) # 通过索引映射填充的值

# 分组填充 transform 进行变换成对数或者其他数字
df.groupby('Grade')['Height'].transform(
                     lambda x: x.fillna(x.mean())).head()
'''
插值函数
'''
s = pd.Series([np.nan, np.nan, 1,
               np.nan, np.nan, np.nan,
               2, np.nan, np.nan])
res = s.interpolate(limit_direction='backward', limit=1)

# 双向插值
res = s.interpolate(limit_direction='both', limit=1)
s.interpolate('nearest').values

s = pd.Series([0,np.nan,10],index=[0,1,10])
s.interpolate() # 默认的线性插值，等价于计算中点的值
s.interpolate(method='index') # 和索引有关的线性插值，计算相应索引大小对应的值

s = pd.Series([0,np.nan,10],
              index=pd.to_datetime(['20200101',
                                    '20200102',
                                    '20200111']))
s.interpolate()
s.interpolate(method='index')

'''
空值判断
None == None
Out[41]: True

None == False
Out[42]: False

None == []
Out[43]: False

None == ''
Out[44]: False
np.nan == np.nan
Out[45]: False

np.nan == None
Out[46]: False

np.nan == False
Out[47]: False
'''
r= np.nan == np.nan # nan 和自身比较也是FALSE
s1 = pd.Series([1, np.nan])

s2 = pd.Series([1, 2])

s3 = pd.Series([1, np.nan])

pd.to_timedelta(['30s', np.nan]) # Timedelta中的NaT

pd.to_datetime(['20200101', np.nan]) # Datetime中的NaT

'''
nan 是float类型 
'''

'''
Nullable类型的性质
'''
pd.Series([np.nan, 1], dtype = 'Int64') # "i"是大写的
pd.Series([np.nan, True], dtype = 'boolean')
pd.Series([np.nan, 'my_str'], dtype = 'string')

pd.Series([np.nan, 0], dtype = 'Int64') + 1
d = pd.Series([np.nan, 0], dtype = 'Int64') == 0
pd.Series([np.nan, 0], dtype = 'Int64') * 0.5 # 只能是浮点

s = pd.Series(['a', 'b'])

s_bool = pd.Series([True, np.nan])
# bool 无法对缺失值进行筛选

df = pd.read_csv('data/learn_pandas.csv')
df = df.convert_dtypes()
#缺失数据的计算和分组
s = pd.Series([2,3,np.nan,4,5])
s.sum()
s.prod()
s.cumsum()
'''
diff, pct_change 这两个函数虽然功能相似，但是对于缺失的处理不同，前者凡是参与缺失计算的部分全部设为了缺失值，而后者缺失值位置会被设为 0% 的变化率
'''
s.diff() # 计算差值并把nan相关的数填写男
s.pct_change() #计算差值百分比，nan相关的填写0并计算本次值和上一次有值得百分比
df_nan = pd.DataFrame({'category':['a','a','b',np.nan,np.nan],
                       'value':[1,3,5,7,9]})
df_nan.groupby('category',
                dropna=False)['value'].mean() # pandas版本大于1.1.0

